/**
 * 维护置顶联系人
 */
import { getLogger, Service } from '@gnlab/utils'
import { MemSubject } from '@gnlab/utils/rx'
import { OrderedMap } from 'immutable'
import type { Services } from '@/services'
import { API } from '@/services/common/api'
import { ContactType, makeContactId, splitContactId } from './definition'

const logger = getLogger('services/contacts/top')

export interface ContactTopInfo {
  id: string // contactId
  ownerWxid: string
  contactUserId: string
  created: number
}

/**
 * 获取置顶联系人列表
 */
interface RawContactTopInfo {
  WxId: string
  ContactUserId: string
  CreateTime: string
}
function formatRawContactTopInfo(raw: RawContactTopInfo): ContactTopInfo {
  return {
    id: makeContactId(raw.WxId, raw.ContactUserId),
    ownerWxid: raw.WxId,
    contactUserId: raw.ContactUserId,
    created: new Date(raw.CreateTime).getTime(),
  }
}
async function getTopContacts(wxids: string[]) {
  return API('/Contact/ContactTopList', {
    data: { wxids },
    formatter(raw: RawContactTopInfo[]) {
      return raw.map(formatRawContactTopInfo)
    },
  })
}

/**
 * 将联系人标记为置顶
 */
async function markTopContact(contactId: string) {
  const [ownerWxid, contactUserId] = splitContactId(contactId)
  return API('/Contact/ContactTop', {
    data: { wxid: ownerWxid, contactUserId },
    formatter(): ContactTopInfo {
      return {
        id: makeContactId(ownerWxid, contactUserId),
        ownerWxid,
        contactUserId,
        created: new Date().getTime(),
      }
    },
  })
}

/**
 * 取消置顶
 */
async function cancelTopContact(contactId: string) {
  const [ownerWxid, contactUserId] = splitContactId(contactId)
  return API('/Contact/CancelContactTop', {
    data: { wxid: ownerWxid, contactUserId },
    formatter() {},
  })
}

export class Tops extends Service<Services> {
  private get qywxs() {
    return this.services.qywxs
  }
  private get contacts() {
    return this.services.contacts
  }

  registered() {
    this.qywxs.bufferPrepared.subscribe(infos => void this.load(infos.map(info => info.wxid)))

    this.qywxs.notAlived.subscribe(info => this.excludeQywx(info.wxid))
  }

  items = new MemSubject(OrderedMap<string, ContactTopInfo>()) // contactId => topInfo

  /**
   * 加载置顶联系人列表
   */
  async load(wxids: string[]) {
    const res = await getTopContacts(wxids)
    if (res.success) {
      this.items.next(this.items.value.concat(res.data.map(v => [v.id, v])))

      // 上面仅加载了“置顶记录“，对应的联系人不一定在联系人列表里（例如一个客户很长时间没说过话，拉近期客户时没拉进来）
      // 需在联系人列表加载完成后，调用 supplementContacts() 保证被置顶的联系人一定被显示出来
      await this.contacts.loading[ContactType.external]
      await this.contacts.loading[ContactType.internal]
      this.supplementContacts()
    } else {
      logger.warn('置顶列表加载失败', res.error)
    }
  }

  /**
   * 尝试将未出现在联系人列表里的“置顶”联系人补充到列表里
   * （仅针对外部联系人，因为目前员工和群都是一次性加载全部的，不会出现需要补充的情况）
   */
  protected supplementContacts() {
    this.items.value.forEach(({ id }) => {
      if (!this.contacts.getOwnedById(id)) {
        void this.contacts.loadInfo({ id }, false)
      }
    })
  }

  /**
   * 将联系人置顶
   */
  async mark(id: string) {
    const contact = this.contacts.getOwnedById(id)
    if (!contact) return null
    const res = await markTopContact(contact.id)
    if (res.success) {
      this.items.next(this.items.value.set(id, res.data))
      return null
    } else {
      logger.warn('联系人置顶失败', res.error)
      return res.error
    }
  }

  /**
   * 联系人取消置顶
   */
  async cancel(id: string) {
    if (!this.items.value.has(id)) return null

    const res = await cancelTopContact(id)
    if (res.success) {
      this.items.next(this.items.value.delete(id))
      return null
    } else {
      logger.warn('联系人取消置顶失败', res.error)
      return res.error
    }
  }

  /**
   * 从置顶结果中排除指定企业微信
   */
  excludeQywx(wxid: string) {
    this.items.next(this.items.value.filter(item => item.ownerWxid !== wxid))
  }
}
